/*
 * Copyright 2008. Mount Sinai Hospital, Toronto, Canada.
 * 
 * Licensed under the Apache License, Version 2.0. You
 * can find a copy of the license at:
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * IN NO EVENT SHALL MOUNT SINAI HOSPITAL BE LIABLE TO ANY PARTY FOR DIRECT, 
 * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST 
 * PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, 
 * EVEN IF MOUNT SINAI HOSPITAL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 
 * DAMAGE.
 * 
 * MOUNT SINAI HOSPITAL SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND 
 * ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". 
 * MOUNT SINAI HOSPITAL HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, 
 * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 
 */

package com.sinai.mshab.widgets;

import java.util.ArrayList;
import java.util.HashMap;

import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.SourcesTabEvents;
import com.google.gwt.user.client.ui.TabListener;
import com.google.gwt.user.client.ui.TabPanel;
import com.google.gwt.user.client.ui.Widget;
import com.sinai.mshab.format.LazyLoaded;

/**
 * This is an extension to TabPanel, this will load the contents of the tabs
 * only when the tab is activated.
 * 
 * @author serge
 * 
 */
public class LazyTabPanel extends TabPanel {

	private HashMap<Label, Widget> placeHoldlerToWidget = new HashMap<Label, Widget>();
	private HashMap<Widget, Object> contetWidgetToTabWidget = new HashMap<Widget, Object>();
	private ArrayList<Widget> loadedWidgets = new ArrayList<Widget>();

	/**
	 * Create a new LazyTabPanel
	 */
	public LazyTabPanel() {
		addTabListener(new LazyTabListener());
	}

	/**
	 * Insert method get's called by add() so we do not need to implement our
	 * code in add()
	 * 
	 * @param widget
	 *            The widget to be added as content
	 * @param tabWidget
	 *            the widget to go in the tab area
	 * @param before
	 *            the index into which to insert this tab.
	 */
	public void insert(Widget widget, Widget tabWidget, int before) {
		Label placeholder = new Label("Loading ... ");
		placeHoldlerToWidget.put(placeholder, widget);
		contetWidgetToTabWidget.put(widget, tabWidget);
		super.insert(placeholder, tabWidget, before);
	}

	/**
	 * Insert method get's called by add() so we do not need to implement our
	 * code in add()
	 * 
	 * @param widget
	 *            The widget to be added as content
	 * @param tabWidgetText
	 *            the text to go in the tab area
	 * @param before
	 *            the index into which to insert this tab.
	 */
	public void insert(Widget widget, String tabWidgetText, int before) {
		Label placeholder = new Label("Loading ... ");
		placeHoldlerToWidget.put(placeholder, widget);
		contetWidgetToTabWidget.put(widget, tabWidgetText);
		super.insert(placeholder, tabWidgetText, before);
	}

	/**
	 * This method get's called before the tab is selected. Will remove the
	 * placeholder widget if it is there and place the real page.
	 * 
	 * @param tabIndex
	 */
	private void beforeTabSelected(int tabIndex) {
		Widget selectedWidget = getWidget(tabIndex);

		// if not loaded already
		if (!contetWidgetToTabWidget.containsKey(selectedWidget)
				&& selectedWidget instanceof Label) {

			// find the widget associated with this placeholder.
			Widget content_widget = placeHoldlerToWidget.get(selectedWidget);

			// if instance of lazy loaded, load the widget
			if (content_widget instanceof LazyLoaded
					&& !loadedWidgets.contains(content_widget)) {
				((LazyLoaded) content_widget).loadWidget();
				loadedWidgets.add(content_widget);
			}

			// remove tab and re-insert what was originally intended.
			remove(tabIndex);

			// check if the tab is a widget or string
			Object tab = contetWidgetToTabWidget.get(content_widget);
			if (tab instanceof String) {
				LazyTabPanel.super.insert(content_widget, (String) tab,
						tabIndex);
			} else if (tab instanceof Widget) {
				LazyTabPanel.super.insert(content_widget, (Widget) tab,
						tabIndex);
			}

		}
		afterTabSelected(tabIndex);
	}
	
	/**
	 * This method get's called after the tab has been succesfully selected.
	 */
	public void afterTabSelected(int index) {
		
	}

	/**
	 * This tab listener will check which tab is desired to be loaded, and will
	 * load the content of this tab if it hasn't already been loaded.
	 * 
	 * @author serge
	 * 
	 */
	private class LazyTabListener implements TabListener {
		public boolean onBeforeTabSelected(SourcesTabEvents sender, int tabIndex) {
			beforeTabSelected(tabIndex);
			return true;
		}

		public void onTabSelected(SourcesTabEvents sender, int tabIndex) {

		}
	}
	
	/**
	 * Clears our widget lookups.
	 */
	public void clear() {
		placeHoldlerToWidget.clear();
		contetWidgetToTabWidget.clear();
		loadedWidgets.clear();
		super.clear();
	}
}
